using System;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;

namespace Gj
{
    public enum ControlType
    {
        Target,
        Object
    }

    public class ControlService : GameService
    {
        private const int objectKey = 0x8000;
        private const int targetKey = 0xc000;
        public static ControlService single;

        public List<Control> list;
        private Dictionary<int, object[]> objectMap;

        private Dictionary<int, object[]> targetMap;
        public List<int> tmp;

        static ControlService()
        {
            single = new ControlService();
        }

        public void OnDestroy()
        {
            single = new ControlService();
        }

        public void OnInit()
        {
            targetMap = new Dictionary<int, object[]>();
            objectMap = new Dictionary<int, object[]>();
            list = new List<Control>();
            tmp = new List<int>();
        }

        public void OnUpdate()
        {
            
        }

        public void OnReady()
        {
            for (var i = 0; i < list.Count; i++) list[i].OnReady();
        }

        public void OnFinish()
        {
            for (var i = 0; i < list.Count; i++) list[i].OnFinish();
        }

        public int MakeKey(ControlType type, int id)
        {
            var key = 0;
            switch (type)
            {
                case ControlType.Object:
                    key = objectKey | id;
                    break;
                case ControlType.Target:
                    key = targetKey | id;
                    break;
            }

            return key;
        }

        public ObjectInfo GetInfo(int key)
        {
            var target = key & 0xf000;
            switch (target)
            {
                case objectKey:
                    return GetObject(key & 0xfff);
                case targetKey:
                    return GetTarget(key & 0xfff);
            }

            return null;
        }

        public void SetObjects(object[] arr)
        {
            foreach (object[] obj in arr) SetObject(obj);
        }

        public void SetObject(object[] obj)
        {
            objectMap.Add(Convert.ToInt32(obj[(byte)OBJECT_INFO.ID]), obj);
        }

        public ObjectInfo GetObject(int objectId)
        {
            return new ObjectInfo(objectMap[objectId]);
        }

        public void SetTarget(object[] obj)
        {
            targetMap.Add(Convert.ToInt32(obj[(byte)OBJECT_INFO.ID]), obj);
        }

        public ObjectInfo GetTarget(int targetId)
        {
            return new ObjectInfo(targetMap[targetId]);
        }

        public Control Get(Entity e)
        {
            var manager = ObjectService.EntityManager;
            if (manager.HasComponent<EntityData>(e)) return list[manager.GetComponentData<EntityData>(e).index];

            return null;
        }

        private int GetIndex()
        {
            if (tmp.Count > 0)
            {
                var i = tmp[0];
                tmp.RemoveAt(0);
                return i;
            }

            return list.Count;
        }

        private int Add(Control element)
        {
            var i = GetIndex();
            if (i == list.Count)
                list.Add(element);
            else
                list[i] = element;

            return i;
        }

        private void Remove(Control element)
        {
            var i = element.GetIndex();
            list[i] = null;
            tmp.Add(i);
        }

        public BaseControl MakeControl(GameObject obj)
        {
            var baseControl = obj.GetComponent<BaseControl>();
            baseControl.Init(baseControl.detail, 0, null, Add(baseControl));
            baseControl.GameObject.SetActive(true);
            return baseControl;
        }

        public BaseControl MakeControl(string name, string skinName, ObjectControl control, Vector3 position,
            Quaternion rotation, GameObject master)
        {
            var baseControl = ObjectService.single.MakeControl(name).GetComponent<BaseControl>();
            baseControl.transform.SetPositionAndRotation(position, rotation);
            baseControl.detail.skin = skinName;
            baseControl.Init(baseControl.detail, control, null, Add(baseControl));
            baseControl.GameObject.SetActive(true);
            return baseControl;
        }

        public BaseControl MakeControl(string name, ObjectControl control, Vector3 position, Quaternion rotation,
            GameObject master)
        {
            var baseControl = ObjectService.single.MakeControl(name).GetComponent<BaseControl>();
            baseControl.transform.SetPositionAndRotation(position, rotation);
            baseControl.Init(baseControl.detail, control, null, Add(baseControl));
            baseControl.GameObject.SetActive(true);
            return baseControl;
        }

        public BaseControl MakeControl(string name, ObjectInfo objInfo, ObjectControl control, Vector3 position,
            Quaternion rotation, GameObject master)
        {
            var baseControl = ObjectService.single.MakeControl(name).GetComponent<BaseControl>();
            baseControl.transform.SetPositionAndRotation(position, rotation);
            objInfo.baseInfo = baseControl.detail.baseInfo;
            baseControl.Init(objInfo, control, null, Add(baseControl));
            baseControl.GameObject.SetActive(true);
            return baseControl;
        }

        public BaseControl MakeControl(ObjectInfo objInfo, Type type, ObjectControl control, Vector3 position,
            Quaternion rotation, GameObject master)
        {
            var baseControl =
                ObjectService.single.MakeEmpty(type, "element" + objInfo.refInfo.id, position, rotation) as BaseControl;
            baseControl.Init(objInfo, control, master, Add(baseControl));
            baseControl.GameObject.SetActive(true);
            return baseControl;
        }

        public void DestroyControl(BaseControl control)
        {
            Remove(control);
            control.GameObject.SetActive(false);
        }
    }
}